<?php

require_once 'AbstractAnalyser.class.php';
require_once 'Log.class.php';

/**
 * @author Frederic Bouchery
 * 
 */
class Quacophonie {
	private $_messageRegistry = array();
	private $_analysers = array();
	
	private $_filename = null;
	private $_tokens = null;
	private $_index = null;
	
	public function __construct() {
		$dir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Analyser'. DIRECTORY_SEPARATOR;
		foreach( glob($dir . '*.class.php') as $filename) {
			$class = 'Analyser_' . basename($filename, '.class.php');
			require $filename;
			Log::debug('load "%s" class', $class);
			$this->_analysers[] = new $class($this);
		}		
	}
	
	public function register($event, $callback) {
		foreach( (array)$event as $evt ) {
			if( ! isset($this->_messageRegistry[$evt]) ) {
				$this->_messageRegistry[$evt] = array();
			}
			Log::debug('register event "%s" to "%s"', $evt, is_array($callback)? get_class($callback[0]) . '->' . $callback[1] : $callback);
			$this->_messageRegistry[$evt][] = $callback;
		}
	}
		
	private function _sendToCallback( $key, $event, $parameters ) {
		$sent = false;
		if( isset( $this->_messageRegistry[$key] )) {
			foreach($this->_messageRegistry[$key] as $callback ) {
			    Log::debug('Send event : %s', $key);
				call_user_func($callback, $event, $parameters);
				$sent = true;	
			}
		}
		return $sent;
	}

	public function send($event, $parameters) {
		$sent = false;
		if( $this->_sendToCallback('*', $event, $parameters) ) {
			$sent = true;
		}
		$decomp = explode('.', $event);
		$key = '';
		$len = count($decomp) - 1;
		for( $i = 0; $i < $len; $i++) {
			$key .= $decomp[$i] . '.';
			if( $this->_sendToCallback($key . '*', $event, $parameters) ) {
				$sent = true;	
			}
		}
		if( $this->_sendToCallback($key . $decomp[$i], $event, $parameters) ) {
			$sent = true;
		}
		//if( ! $sent ) Log::debug('Event %s not sent', $event);
	}
	
	private function _resetAnalysers() {
		Log::debug('Reset analysers');
		foreach( $this->_analysers as $analyser ) {
			$analyser->reset();
		}
	}
	public function getToken( $offset = 0 ) {
        $token = $this->_tokens[$this->_index + $offset];
        if( ! is_array( $token ) ) {
            $token = array(T_CHARACTER, $token, 0);
        }
        return $token;
    }
    
    public function getIndex() {
    	return $this->_index;
    }
    
	/**
	 * @param string $filename File to parse
	 * @throw QuacophonieException
	 */
	public function parse($filename) {
		static $tCharacters = array(
			'{' => 'T_OPEN_CURLY_BRACKET',
			'}' => 'T_CLOSE_CURLY_BRACKET',
			'(' => 'T_OPEN_ROUND_BRACKET',
			')' => 'T_CLOSE_ROUND_BRACKET',
			'[' => 'T_OPEN_SQUARE_BRACKET',
			']' => 'T_CLOSE_SQUARE_BRACKET',
			',' => 'T_COMMA',
			';' => 'T_SEMICOLON',
			'=' => 'T_ASSIGN'
		);
		
		Log::debug('Parse file : %s', $filename);
		if( ! is_readable( $filename ) ) {
			throw new QuacophonieException(sprintf('Could not read file : %s', $filename));
		} 
		
		$this->_resetAnalysers();
		
		$this->_filename = $filename;
		$this->_tokens = token_get_all( file_get_contents($filename) );
		$this->_index = 0;
		$len = count($this->_tokens);
		while( $this->_index  < $len) {
			$token = $this->getToken();
			if( $token[0] === T_CHARACTER) {
				if( isset( $tCharacters[$token[1]])) $type = $tCharacters[$token[1]];
				else $type = 'T_CHARACTER';
				$this->send('token.' . $type, $token);
			} else {
				$this->send('token.' . token_name($token[0]), $token);
			}
			$this->_index++;
		}
	}
	
	
}